﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Controls;

using Microsoft.SharePoint.Client;

using DevExpress.Utils;
using DevExpress.Xpf.Data;
using DevExpress.Xpf.Editors.Settings;
using DevExpress.Xpf.Grid;

using SBPweb.RIA.Client.Common.Collections;
using SBPweb.RIA.Client.Contracts.Base;
using SBPweb.RIA.Client.Controls.Base;
using SBPweb.RIA.Client.Controls.Extensions;

using SBPweb.Sharepoint.Client.Library.Lists;

using SBPweb.Sharepoint.Client.Controls.Fields;
using SBPweb.Sharepoint.Client.Controls.Users;

namespace SBPweb.Sharepoint.Client.Controls.Lists
{

    public partial class ListGrid : UserControlBase
    {

        #region Fields

        private List list;
        private ListCollection lists;
        private View view;
        private ListItemCollection items;
        private ListItemValuesDescriptor itemValuesDescriptor;

        private List userList;
        private ListItemCollection users;

        #endregion

        #region Construcor logic

        public ListGrid()
            : base()
        {
            InitializeComponent();
        }

        #endregion

        #region Dependencies

        public static readonly DependencyProperty ListNameProperty = DependencyProperty.Register("ListName", typeof(string), typeof(ListGrid), null);

        public static readonly DependencyProperty UsersSourceProperty = DependencyProperty.Register("UsersSource", typeof(ObservableList<FieldUserValue>), typeof(ListGrid), null);

        #endregion

        #region Properties
        
        public ClientContext SharepointContext
        {
            get;
            private set;
        }

        public string ListName
        {
            get
            {
                return GetValue<string>(ListNameProperty);
            }
            set
            {
                SetValue<string>(ListNameProperty, value, "ListName");
            }
        }

        public ObservableList<FieldUserValue> UsersSource
        {
            get
            {
                return GetValue<ObservableList<FieldUserValue>>(UsersSourceProperty);
            }
            set
            {
                SetValue<ObservableList<FieldUserValue>>(UsersSourceProperty, value, "UsersSource");
            }
        }

        public TableView View
        {
            get
            {
                return gcItems.View as TableView;
            }
        }

        #endregion

        #region Event handlers

        protected override void InitializeHandlers()
        {
            base.InitializeHandlers();
        }
        
        protected override void OnLoaded(object sender, RoutedEventArgs e)
        {
            base.OnLoaded(sender, e);
        }

        public void InitializeContext(ClientContext context)
        {
            Dispatcher.BeginInvoke(() =>
            {
                SharepointContext = context;
                if (context != null)
                {
                    if (string.IsNullOrEmpty(ListName))
                    {
                        ListName = "Tasks";
                    }

                    lists = context.Web.Lists;
                    FetchList();
                }
            });
        }

        public void FetchList()
        {
            list = lists.GetByTitle(ListName);

            gcItems.ShowLoadingPanel = true;

            list.Context.Load(list.Fields);
            list.Context.Load(list.Views);
            list.Context.ExecuteQueryAsync(onListSucceeded, onListFailed);
        }

        private void onListSucceeded(object sender, ClientRequestSucceededEventArgs args)
        {
            view = list.Views.FindDefaultView();

            if (view == null)
            {
                return;
            }

            list.Context.Load(view, x => x.ViewFields);
            list.Context.ExecuteQueryAsync(onViewSucceeded, onViewFailed);
        }

        private void onListFailed(object sender, ClientRequestFailedEventArgs args)
        {
            this.Dispatcher.BeginInvoke(() => gcItems.ShowLoadingPanel = false);
            throw args.Exception;
        }
        
        private void onViewSucceeded(object sender, ClientRequestSucceededEventArgs args)
        {
            this.Dispatcher.BeginInvoke(() => PopulateColumns());
        }

        private void onViewFailed(object sender, ClientRequestFailedEventArgs args)
        {
            this.Dispatcher.BeginInvoke(() => gcItems.ShowLoadingPanel = false);
            throw args.Exception;
        }

        protected virtual void PopulateColumns()
        {
            CamlQuery query = new CamlQuery() { ViewXml = view.ViewQuery };
            List<string> fieldNames = view.ViewFields.ToList();
            CamlOrderings fieldOrders = query.GetOrderings();

            if (!gcItems.AutoPopulateColumns)
            {
                gcItems.ClearGrouping();
                gcItems.Columns.Clear();

                foreach (var f in fieldNames)
                {
                    Field field = list.Fields.FindField(x => x.StaticName == f);
                    GridColumn gc = PopulateColumn(field, fieldNames, fieldOrders);
                    gcItems.Columns.Add(gc);
                }

                foreach (var field in list.Fields)
                {
                    if (!field.Hidden && !fieldNames.Contains(field.StaticName))
                    {
                        GridColumn gc = PopulateColumn(field, fieldNames, fieldOrders);
                        gcItems.Columns.Add(gc);
                    }
                }
            }

            ListItemValuesFactory fac = new ListItemValuesFactory("ListName", list.Fields);
            IList ols = fac.CreateListInstance();
            gcItems.DataSource = ols;
                        
            items = list.GetItems(query);

            itemValuesDescriptor = new ListItemValuesDescriptor(fac, items, ols);

            list.Context.Load(items);
            list.Context.ExecuteQueryAsync(onItemsSucceeded, onItemsFailed);
        }

        private GridColumn PopulateColumn(Field field, List<string> fieldNames, CamlOrderings fieldOrders)
        {
            string fieldName = field.StaticName;
            return new GridColumn()
            {
                FieldName = fieldName,
                Header = field.Title,
                ReadOnly = field.ReadOnlyField,
                AllowSorting = field.Sortable ? DefaultBoolean.True : DefaultBoolean.False,
                AllowColumnFiltering = field.Filterable ? DefaultBoolean.True : DefaultBoolean.False,
                BestFitMode = DevExpress.Xpf.Core.BestFitMode.Smart,
                AllowBestFit = DefaultBoolean.True,
                Visible = fieldNames.Contains(fieldName),
                SortIndex = fieldOrders.IndexOf(fieldName),
                SortOrder = fieldOrders.ContainsField(fieldName) ? (DevExpress.Data.ColumnSortOrder)(int)(fieldOrders[fieldName].Value) : DevExpress.Data.ColumnSortOrder.None,
                EditSettings = PopulateColumnSetting(field),
            };
        }

        private BaseEditSettings PopulateColumnSetting(Field field)
        {
            switch(field.FieldTypeKind)
            {
                default:
                    return new DevExpress.Xpf.Editors.Settings.TextEditSettings()
                    {
                    };
                case FieldType.Note:
                    return new DevExpress.Xpf.Editors.Settings.MemoEditSettings()
                    {
                    };
                case FieldType.DateTime:
                    return new DevExpress.Xpf.Editors.Settings.DateEditSettings()
                    {
                    };
                case FieldType.Choice:
                    return new ChoiceEditSettings()
                    {
                        Field = field as FieldChoice,
                    };
                case FieldType.Currency:
                case FieldType.Number:
                    return new NumberEditSettings()
                    {
                        Field = field as FieldNumber,
                    };
                case FieldType.User:
                    FetchUsers();
                    return new UserEditSettings()
                    {
                        Field = field as FieldUser,
                        UsersSource = this.UsersSource
                    };
            }
        }
        
        private void onItemsSucceeded(object sender, ClientRequestSucceededEventArgs args)
        {
            this.Dispatcher.BeginInvoke(() => PopulateRows());
        }

        private void onItemsFailed(object sender, ClientRequestFailedEventArgs args)
        {
            this.Dispatcher.BeginInvoke(() => gcItems.ShowLoadingPanel = false);
            throw args.Exception;
        }
        
        protected virtual void PopulateRows()
        {
            foreach (var item in itemValuesDescriptor.SourceList)
            {
                itemValuesDescriptor.TargetList.Add(itemValuesDescriptor.Factory.CreateItemInstance(item));
            }
            View.BestFitColumns();
            gcItems.ShowLoadingPanel = false;
        }

        #region UsersSource population

        private void FetchUsers()
        {
            if (this.UsersSource == null)
            {
                this.UsersSource = new ObservableList<FieldUserValue>();
            }
            if (this.userList == null)
            {
                this.userList = this.SharepointContext.Web.SiteUserInfoList;
                this.SharepointContext.Load(userList);
                this.SharepointContext.ExecuteQueryAsync(onUserListSucceeded, onUserListFailed);
            }
        }

        private void onUserListSucceeded(object sender, ClientRequestSucceededEventArgs args)
        {
            users = userList.GetItems(CamlQuery.CreateAllItemsQuery());
            SharepointContext.Load(users);
            SharepointContext.LoadQuery(users.Include(x => x.ContentType));
            SharepointContext.ExecuteQueryAsync(onUserListItemsSucceeded, onUserListItemsFailed);
        }

        private void onUserListFailed(object sender, ClientRequestFailedEventArgs args)
        {
            throw args.Exception;
        }

        private void onUserListItemsSucceeded(object sender, ClientRequestSucceededEventArgs args)
        {
            Dispatcher.BeginInvoke(() =>
            {
                foreach (var user in users)
                {
                    //string email = user["EMail"] as string;
                    //if (!string.IsNullOrEmpty(email))
                    //{
                        int id = Convert.ToInt32(user["ID"]);
                        string userName = user["Name"] as string;
                        var fuv = FieldUserValue.FromUser(userName);
                        fuv.LookupId = id;
                        UsersSource.Add(fuv);
                    //}
                }
            });
        }

        private void onUserListItemsFailed(object sender, ClientRequestFailedEventArgs args)
        {
            throw args.Exception;
        }

        #endregion
                
        #endregion

    }
        
    //public class ListItemValueConverter : IValueConverter
    //{

    //    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    //    {
    //        RowData rd = value as RowData;
    //        ListItemValues item = rd.Row as ListItemValues;
    //        string fieldName = parameter as string;
    //        return item.GetValue(fieldName);
    //    }

    //    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    //    {
    //        throw new NotImplementedException();
    //    }

    //}

}